package com.work.service.main.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.work.constant.ExceptionDescription;
import com.work.dto.main.ShipBillStorageSearchDTO;
import com.work.entity.main.ShipBillStorage;
import com.work.mapper.main.ShipBillStorageMapper;
import com.work.service.main.IShipBillStorageService;
import com.work.service.main.ITShipBillStatusService;
import com.work.vo.main.*;
import lombok.AllArgsConstructor;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.utils.Func;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * 场存接口实现
 *
 * @author ：dujianyu
 * @since ：Created in 2024/3/14 10:00
 */
@Service
@AllArgsConstructor
public class ShipBillStorageServiceImpl extends BaseServiceImpl<ShipBillStorageMapper, ShipBillStorage> implements IShipBillStorageService {

    private ITShipBillStatusService itShipBillStatusService;

    private static final BigDecimal DECIMAL_ZERO = BigDecimal.ZERO;
    private static final Integer INTEGER_ZERO = 0;

    @Override
    public Long addNewShipStorage(ShipBillStorage entity) {
        Long isExistStorageId = isShipBillStorageExist(entity.getTShipBillId(), entity.getAreaId(), entity.getPositionId(), entity.getSpot(), entity.getPackageType());
        if (!Func.isNull(isExistStorageId)) {
            return isExistStorageId;
        }


        if (super.saveOrUpdate(entity)) {
            return entity.getId();
        } else {
            throw new RuntimeException(ExceptionDescription.DB_ERROR + "创建新场存记录失败");
        }
    }

    @Override
    public boolean addStorageWithGoodPositionId(Long storageId, Integer piece, BigDecimal ton, Long goodsPositionId) {
        ShipBillStorage update = getStorageById(storageId);
        update.setGoodsPositionId(goodsPositionId);
        update.setPiece((Func.isNull(update.getPiece()) ? INTEGER_ZERO : update.getPiece()) + piece);
        update.setTon((Func.isNull(update.getTon()) ? DECIMAL_ZERO : update.getTon()).add(ton));
        return super.saveOrUpdate(update);
    }

    @Override
    public boolean addStorage(Long storageId, Integer piece, BigDecimal ton) {
        ShipBillStorage update = getStorageById(storageId);
        update.setPiece((Func.isNull(update.getPiece()) ? INTEGER_ZERO : update.getPiece()) + piece);
        update.setTon((Func.isNull(update.getTon()) ? DECIMAL_ZERO : update.getTon()).add(ton));
        return super.saveOrUpdate(update);
    }

    @Override
    public boolean subStorageWithGoodPositionId(Long storageId, Integer piece, BigDecimal ton, Long goodsPositionId) {
        ShipBillStorage update = getStorageById(storageId);
        update.setGoodsPositionId(goodsPositionId);
        update.setPiece((Func.isNull(update.getPiece()) ? INTEGER_ZERO : update.getPiece()) - piece);
        update.setTon((Func.isNull(update.getTon()) ? DECIMAL_ZERO : update.getTon()).subtract(ton));
        return super.saveOrUpdate(update);
    }

    @Override
    public boolean subStorage(Long storageId, Integer piece, BigDecimal ton) {
        ShipBillStorage update = getStorageById(storageId);
        update.setPiece((Func.isNull(update.getPiece()) ? INTEGER_ZERO : update.getPiece()) - piece);
        update.setTon((Func.isNull(update.getTon()) ? DECIMAL_ZERO : update.getTon()).subtract(ton));
        return super.saveOrUpdate(update);
    }

    @Override
    public PieceTonVO getStorageByTransportBillId(ShipBillStorageSearchDTO dto) {
        PieceTonVO res = new PieceTonVO();
        res.setPiece(INTEGER_ZERO);
        res.setTon(DECIMAL_ZERO);

        QueryWrapper<ShipBillStorage> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(ShipBillStorage::getIsDeleted,0)
                .eq(ShipBillStorage::getIsActive, "Y")
                .eq(ShipBillStorage::getTransportBillId, dto.getTransportBillId());
        List<ShipBillStorage> shipBillStorages = baseMapper.selectList(queryWrapper);

        if (!Func.isNull(shipBillStorages) && !Func.isEmpty(shipBillStorages)) {
            for (ShipBillStorage storage : shipBillStorages) {
                res.setPiece(res.getPiece() + storage.getPiece());
                res.setTon(res.getTon().add(storage.getTon()).setScale(3, RoundingMode.UP));
            }
        }

        return res;
    }

    @Override
    public IPage<ShipBillStorageVO> selectShipBillStoragePage(IPage<ShipBillStorageVO> page, ShipBillStorageSearchDTO dto) {
        List<ShipBillStorageVO> data = baseMapper.selectShipBillStorageList(dto, page);
        return page.setRecords(data);
    }

    @Override
    public List<ShipBillStorageVO> selectShipBillStorageList(ShipBillStorageSearchDTO dto) {
        return baseMapper.selectShipBillStorageList(dto, null);
    }

    @Override
    public PieceTonVO selectShipBillStorageTotal(ShipBillStorageSearchDTO dto) {
        return baseMapper.selectShipBillStorageTotal(dto);
    }

    @Override
    public ShipBillStorageVO getStorageDetail(ShipBillStorageSearchDTO dto) {
        ShipBillStorageVO res = new ShipBillStorageVO();
        List<ShipBillStorageVO> list = baseMapper.selectShipBillStorageList(dto, null);
        if(!Func.isNull(list) && !Func.isEmpty(list)) {
            res = list.get(0);
        }
        return res;
    }

    @Override
    public boolean clearStorage(String transportBillId) {
        CheckBillClearVO checkBillClear = itShipBillStatusService.checkBillClear(Func.toLong(transportBillId));
        if (Func.isNull(checkBillClear.getIsFinish()) || "N".equals(checkBillClear.getIsFinish())) {
            throw new RuntimeException(ExceptionDescription.LOGIC_ERROR + "没有该舱单信息/该舱单未完结");
        }

        ShipBillStorageSearchDTO searchDTO = new ShipBillStorageSearchDTO();
        searchDTO.setTransportBillId(Func.toLong(transportBillId));
        List<ShipBillStorageVO> storages = selectShipBillStorageList(searchDTO);
        if (Func.isNull(storages) || Func.isEmpty(storages)) {
            throw new RuntimeException(ExceptionDescription.LOGIC_ERROR + "没有货垛可情空");
        }

        int allPiece = 0;
        BigDecimal allTon = new BigDecimal(0);
        for (ShipBillStorageVO item : storages) {
            allPiece += item.getPiece();
            allTon = allTon.add(item.getTon());
        }
        if (allPiece != 0) {
            throw new RuntimeException(ExceptionDescription.LOGIC_ERROR + "件数不为0");
        }
        if (!"存栈".equals(checkBillClear.getShipNameZh()) && allTon.compareTo(new BigDecimal(500)) >= 0) {
            throw new RuntimeException(ExceptionDescription.LOGIC_ERROR + "非存栈剩余吨数大于等于500吨");
        }

        List<ShipBillStorage> updateList = new ArrayList<>();
        for (ShipBillStorageVO item : storages) {
            ShipBillStorage update = new ShipBillStorage();
            update.setId(item.getId());
            update.setPiece(0);
            update.setTon(new BigDecimal(0));

            updateList.add(update);
        }
        return super.saveOrUpdateBatch(updateList);
    }

    @Override
    public IPage<StorageByPositionVO> selectStorageByPositionPage(IPage<StorageByPositionVO> page, ShipBillStorageSearchDTO dto) {
        List<StorageByPositionVO> data = baseMapper.selectStorageByPositionList(dto, page);
        return page.setRecords(data);
    }

    @Override
    public PieceTonVO selectStorageByPositionTotal(ShipBillStorageSearchDTO dto) {
        return baseMapper.selectStorageByPositionTotal(dto);
    }

    @Override
    public IPage<StorageByCargoVO> selectStorageByCargoPage(IPage<StorageByCargoVO> page, ShipBillStorageSearchDTO dto) {
        List<StorageByCargoVO> data = baseMapper.selectStorageByCargoList(dto, page);
        return page.setRecords(data);
    }

    @Override
    public PieceTonVO selectStorageByCargoTotal(ShipBillStorageSearchDTO dto) {
        return baseMapper.selectStorageByCargoTotal(dto);
    }

    @Override
    public IPage<StorageByShipVO> selectStorageByShipPage(IPage<StorageByShipVO> page, ShipBillStorageSearchDTO dto) {
        List<StorageByShipVO> data = baseMapper.selectStorageByShipList(dto, page);
        return page.setRecords(data);
    }

    @Override
    public PieceTonVO selectStorageByShipTotal(ShipBillStorageSearchDTO dto) {
        return baseMapper.selectStorageByShipTotal(dto);
    }

    @Override
    public IPage<StorageByPositionDetailVO> selectStorageByPositionDetailPage(IPage<StorageByPositionDetailVO> page, ShipBillStorageSearchDTO dto) {
        List<StorageByPositionDetailVO> data = baseMapper.selectStorageByPositionDetailList(dto, page);
        return page.setRecords(data);
    }

    @Override
    public IPage<StorageByPositionTallyVO> selectStorageByPositionTallyPage(IPage<StorageByPositionTallyVO> page, ShipBillStorageSearchDTO dto) {
        List<StorageByPositionTallyVO> data = baseMapper.selectStorageByPositionTallyList(dto, page);
        return page.setRecords(data);
    }

    @Override
    public IPage<StorageByCargoDetailVO> selectStorageByCargoDetailPage(IPage<StorageByCargoDetailVO> page, ShipBillStorageSearchDTO dto) {
        List<StorageByCargoDetailVO> data = baseMapper.selectStorageByCargoDetailList(dto, page);
        return page.setRecords(data);
    }

    @Override
    public IPage<StorageByShipDetailVO> selectStorageByShipDetailPage(IPage<StorageByShipDetailVO> page, ShipBillStorageSearchDTO dto) {
        List<StorageByShipDetailVO> data = baseMapper.selectStorageByShipDetailList(dto, page);
        return page.setRecords(data);
    }

    private ShipBillStorage getStorageById(Long id) {
        ShipBillStorage selectedById = baseMapper.selectById(id);
        if (Func.isNull(selectedById)) {
            throw new RuntimeException(ExceptionDescription.DB_ERROR + "没有场存记录");
        }
        return selectedById;
    }

    private Long isShipBillStorageExist(Long tShipBillId, Long areaId, Long positionId, String spot, String packageType) {
        QueryWrapper<ShipBillStorage> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ShipBillStorage::getIsDeleted, 0)
                .eq(ShipBillStorage::getTShipBillId, tShipBillId)
                .eq(ShipBillStorage::getAreaId, areaId)
                .eq(ShipBillStorage::getPositionId, positionId)
                .eq(ShipBillStorage::getSpot, spot)
                .eq(ShipBillStorage::getPackageType, packageType)
                .last("limit 1");
        ShipBillStorage shipBillStorage = baseMapper.selectOne(queryWrapper);
        if (Func.isNull(shipBillStorage)) {
            return null;
        } else {
            return shipBillStorage.getId();
        }
    }


}
